/**
 * Class that handles an audio driver in wiwann instance in order to produce sound
 *
 */

#ifndef _WIWANNSOUNDTRANSMITTER_H
#define	_WIWANNSOUNDTRANSMITTER_H


#include "wiwannSound.h"

class wiwannSoundTransmitter
{

private:
    WIWANNuint freq   ;
    ALuint hSource ;
    ALuint format ;
    bool errorGen ;
    
public:
    

    bool isPlaying()
    {
        ALint Status;
        alGetSourcei(this->hSource,  AL_SOURCE_STATE, &Status);
        return (Status == AL_PLAYING);
    }
    

    WIWANNuint getFreq()
    {
        return this->freq ;
    }
    WIWANNuint getFormat()
    {
        return this->format ;
    }


    wiwannSoundTransmitter() //constructor
    {
        //alGetError();
        //alGetError();
        //alGetError();
        this->freq = WIWANN_DEFAULT_SOUND_FREQ ;
        this->format = WIWANN_SOUND_FORMAT_MONO16 ;

        this->hSource = NULL ;
        this->errorGen = false ;
        alGetError();
        alGenSources(1,& this->hSource);
        //  std::cout << "\ncree source " << this->hSource ;
        if (alGetError() != AL_NO_ERROR)
        {
            this->errorGen = true ;
            return ;
        }
        this->errorGen = false ;

        ALfloat sourcePos[] = { 0.0, 0.0, 0.0 };
        ALfloat sourceVel[] = { 0.0, 0.0, 0.0 };
        alSourcei ( this->hSource, AL_POSITION, *sourcePos     );
        alSourcei ( this->hSource, AL_VELOCITY, *sourceVel     );
        alSourcePlay(this->hSource);
        //std::cout << "\ncree une source "<<  this->hSource <<"\n" ;
    }

    bool isValid()
    {
        return ! this->errorGen ;
    }

    bool playData(WIWANNuint size , const WIWANNdontcare* data)  //joue en direct, si le wwst est dispo, l'échantillon
    {
        if( this->isPlaying() ) return false ;
        //alGenSources(1, & this->hSource);
        this->queueData(size,data);
        return true ;
    }

    bool setFormat(WIWANNuint mformat)
    {
        format = mformat ;
    }

  

    void cleanInternalBuffers() //Clean all played buffers
    {
        WIWANNuint buffersProcessed =0 ;
        ALuint hBuffer ;
	alGetSourcei(hSource, AL_BUFFERS_PROCESSED, (ALint*) &buffersProcessed);
        while (buffersProcessed > 0)
        {
            alSourceUnqueueBuffers(hSource, 1, &hBuffer );
            alDeleteBuffers( 1,&hBuffer);
            buffersProcessed--;
        }
        alGetSourcei(hSource, AL_BUFFERS_QUEUED, (ALint*) &buffersProcessed);
    }


    void cleanAllInternalBuffers() //Clean all played or playing or non yet plaid buffers
    {
        WIWANNuint buffersProcessed =0 ;
        ALuint hBuffer ;
	alGetSourcei(this->hSource, AL_BUFFERS_QUEUED, (ALint*) &buffersProcessed);
        while (buffersProcessed > 0)
        {
            alSourceUnqueueBuffers(this->hSource, 1, &hBuffer );
            alDeleteBuffers( 1,&hBuffer);
            buffersProcessed--;
        }
        alGetSourcei(hSource, AL_BUFFERS_QUEUED, (ALint*) &buffersProcessed);
    }


     void queueData(WIWANNuint size , const WIWANNdontcare* data) //ajoute un échantillon à la file à jouer
    {
            ALuint hBuffer ;
            ALuint hSourceBis ;

            alGenBuffers( 1, &hBuffer );

           hSourceBis= this->hSource ;
            //std::cout << "\nsize buffer maison: " <<  size ;
            //alBufferData( hBuffer, AL_FORMAT_MONO16,  NULL, 0, WIWANN_DEFAULT_SOUND_FREQ);
             alBufferData( hBuffer, this->getFormat(),  data, size, this->getFreq() );
            //alGetBufferi(hBuffer,AL_SIZE, (ALint*) &buffersProcessed);
            //std::cout << "\nsize buffer chargé: " <<  buffersProcessed;
            //alGetBufferi(hBuffer,AL_FREQUENCY, (ALint*) &buffersProcessed);
            //std::cout << "\nfreq buffer chargé: " <<  buffersProcessed;

            alSourceQueueBuffers(this->hSource,1,&hBuffer);
            alSourcePlay(this->hSource);
    };

    ~wiwannSoundTransmitter() //destructor
    {
        ALuint sourceDeb = this->hSource;
        //std::cout << "\nElDestructor "<<  sourceDeb <<"\n" ;
        alSourceStop(sourceDeb);
        cleanAllInternalBuffers();
        alDeleteSources(1,&sourceDeb);
        //std::cout << "\nok en sortie "<<  sourceDeb <<"\n" ;
    }



    static bool transmittersInit(const char* transmittersDeviceId)
    {
        ALCdevice* Device = alcOpenDevice(NULL);
        //wiwannSoundTransmitter::lastSourceGen = NULL ;
        if (!Device)
            return false;
         ALCcontext* Context = alcCreateContext(Device,NULL);
         if (!Context)
            return false;
         if (!alcMakeContextCurrent(Context))
         {
           // wiwannSoundCheckErrors();
            return false;
         }


        ALfloat ListenerPos[] = {0.0, 0.0, 0.0};

        // Velocity of the listener.
        ALfloat ListenerVel[] = {0.0, 0.0, 0.0};

        // Orientation of the listener. (first 3 elements are "at", second 3 are "up")
        ALfloat ListenerOri[] = {0.0, 0.0, -1.0, 0.0, 1.0, 0.0};

        alListenerfv(AL_POSITION,    ListenerPos);
        alListenerfv(AL_VELOCITY,    ListenerVel);
        alListenerfv(AL_ORIENTATION, ListenerOri);
        return true ;
    }

    static void transmittersGetStrDevices(std::vector<std::string>& Devices)
    {
        // Vidage de la liste
        Devices.clear();

        // Récupération des devices disponibles
        const ALCchar* DeviceList = alcGetString(NULL, ALC_DEVICE_SPECIFIER);

        if (DeviceList)
        {
            // Extraction des devices contenus dans la chaîne renvoyée
            while (strlen(DeviceList) > 0)
            {
                Devices.push_back(DeviceList);
                DeviceList += strlen(DeviceList) + 1;
            }
        }
    }

    static void transmittersShutdown()
    {
        // Récupération du contexte et du device
        ALCcontext* Context = alcGetCurrentContext();
        ALCdevice*  Device  = alcGetContextsDevice(Context);

        // Désactivation du contexte
        alcMakeContextCurrent(NULL);

       // Destruction du contexte
        alcDestroyContext(Context);

        // Fermeture du device
        alcCloseDevice(Device);
                
    }

    static wiwannSoundTransmitter* transmittersGetOne()
    {
        wiwannSoundTransmitter* transmitter = new wiwannSoundTransmitter ;
     
        //std::cout << "\ncreation du p " << transmitter << "\n" ;
        if(! transmitter-> isValid() )
        {
            std::cout << "\nsouce pas valide" ;
            delete transmitter ;
            transmitter = NULL;
        }
        return transmitter ;
    }

};








/*
 * code pour attendre sans prendre de ressources systemes
 *
http://benbritten.com/2010/05/04/streaming-in-openal/
-(void)rotateBufferThread:(NSString*)soundKey
{
	NSAutoreleasePool * apool = [[NSAutoreleasePool alloc] init];
	BOOL stillPlaying = YES;
	while (stillPlaying) {
		stillPlaying = [self rotateBufferForStreamingSound:soundKey];
		if (interrupted) 	{
			// slow down our thread during interruptions
			[NSThread sleepForTimeInterval:kBufferRefreshDelay * 3];
		} else {
			// normal thread delay
			[NSThread sleepForTimeInterval:kBufferRefreshDelay];
		}
	}
	[apool release];
}
 */
#endif	/* _WIWANNSOUNDTRANSMITTER_H */